﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Data;
using System.Windows.Media.Imaging;

namespace WeatherFrame
{
    public partial class WeatherItemView : UserControl, IDataContextChangedHandler<WeatherItemView>
    {
        public WeatherItemView()
        {
            InitializeComponent();
            DataContextChangedHelper<WeatherItemView>.Bind(this);
        }

        Brush trans = new SolidColorBrush(Color.FromArgb(0, 255, 255, 255));
        Brush transWhite = new SolidColorBrush(Color.FromArgb(120, 255, 255, 255));
        private void TextBlock_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            //UNCOMMENT FOR IMAGE TESTING
            //var wi = DataContext as WeatherItem;
            //wi.WeatherCondition = wi.WeatherCondition;

            double totalTime = 0.2;
            double moveBy = -750;
            AnimateTranslation(totalTime, ConditionGrid,  ConditionGrid.Margin.Left < 0 ? 0 : moveBy, initialBottomMargin , 15);
            showWeatherDetails = false;
            e.Handled = true;
        }

        private static void AnimateTranslation(double time, FrameworkElement element, double endX, double endY, int steps)
        {
            ObjectAnimationUsingKeyFrames da = new ObjectAnimationUsingKeyFrames { 
                Duration = new Duration(TimeSpan.FromSeconds(time)) 
            };
            Thickness th = element.Margin;
            double startx = th.Left;
            double moveX = endX - startx;
            double stepx = moveX / steps;
            double starty = th.Bottom;
            double moveY = endY - starty;
            double stepy = moveY / steps;
            for (int i = 0; i < steps; i++)
            {
                da.KeyFrames.Add(new DiscreteObjectKeyFrame
                {
                    KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds((time * (i + 1)) / steps)),
                    Value = new Thickness(startx + stepx * (i + 1), th.Top, th.Right, starty + stepy * (i + 1))
                });
            }
            Storyboard.SetTarget(da, element);
            Storyboard.SetTargetProperty(da, new PropertyPath("Margin"));
            Storyboard sb = new Storyboard();
            sb.Children.Add(da);
            sb.Begin();
        }

        private void TextBlock_MouseLeftButtonDown_1(object sender, MouseButtonEventArgs e)
        {
            App.ViewModel.UseCelsius = !App.ViewModel.UseCelsius;
        }

        internal void Image_ImageOpened(object sender, RoutedEventArgs e)
        {
            var wi = (WeatherItem)DataContext;
            //wi.IsWaitingForWeather = false;
            Image im = (Image)sender;
            Storyboard sb = new Storyboard();
            DoubleAnimation da = new DoubleAnimation { From = 0, To = 1, Duration = new Duration(TimeSpan.FromSeconds(0.3)) };
            Storyboard.SetTarget(da, im);
            Storyboard.SetTargetProperty(da, new PropertyPath("Opacity"));
            sb.Children.Add(da);
            DoubleAnimation da2 = new DoubleAnimation { From = 0, To = 0.8, Duration = da.Duration };
            Storyboard.SetTarget(da2, ImageInfo);
            Storyboard.SetTargetProperty(da2, new PropertyPath("Opacity"));
            sb.Children.Add(da2);
            sb.Begin();
            sb.Completed += new EventHandler(sb_Completed);
        }

        void sb_Completed(object sender, EventArgs e)
        {
            var wi = (WeatherItem)DataContext;
            if ((wi.Image == null) || (wi.Image.MediumUri == null))
            {
                WeatherImageMedium.Source = null;
            }
            else
            {
                LowProfileImageLoader.SetUriSource(WeatherImageMedium, new Uri(wi.Image.MediumUri));
            }
        }

        #region IDataContextChangedHandler<WeatherItemView> Members

        public void DataContextChanged(WeatherItemView sender, DependencyPropertyChangedEventArgs e)
        {
            WeatherItem wi = e.NewValue as WeatherItem;
            if (wi == null) return;
            wi.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(wi_PropertyChanged);
            UpdateTemp();
        }

        void wi_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName.Equals("WeatherCondition")) ResetView();
            if (!e.PropertyName.Contains("TempTextMax")) return;
            UpdateTemp();
        }

        private void UpdateTemp()
        {
            WeatherItem wi = DataContext as WeatherItem;
            if (wi == null) return;
            int min = wi.MinTempC;
            int max = wi.MaxTempC;
            Visibility visMin = min == int.MinValue ? Visibility.Collapsed : Visibility.Visible;
            Visibility visMax = min == max ? Visibility.Collapsed : Visibility.Visible;
            if (min == int.MinValue) visMax = Visibility.Collapsed;
            TempLeft.Visibility = visMin;
            MinTempElement.Visibility = visMin;
            TempUnit.Visibility = visMin;
            TempConnector.Visibility = visMax;
            MaxTempElement.Visibility = visMax;
            if (min == int.MinValue) return;
            ((TextBlock)MinTempElement.Child).Text = wi.TempTextMin+"°";
            ((TextBlock)MaxTempElement.Child).Text = wi.TempTextMax+"°";
            MinTempElement.Measure(new Size(1000, 1000));
            MaxTempElement.Measure(new Size(1000, 1000));
            double scaleStart = -10, scaleEnd = 40;
            //scaleStart = 7; scaleEnd = 10; //- for testing high and low temperatures
            double scaleMin = Math.Min(min, scaleStart); // normal low end of scale is -10C
            double scaleMax = Math.Max(max, scaleEnd); // normal high end of scale is 35C
            double w = 564;// TempPanel.ActualWidth;
            double minpos = w * (min - scaleMin) / (scaleMax - scaleMin);
            double maxpos = w * (max - scaleMin) / (scaleMax - scaleMin);
            TempLeft.Width = Math.Max(0, minpos - MinTempElement.DesiredSize.Width / 2);
            TempConnector.Width = Math.Max(12, maxpos - minpos - MinTempElement.DesiredSize.Width / 2 - MaxTempElement.DesiredSize.Width / 2);
            TempUnitText.Text = App.ViewModel.UseCelsius ? "CELSIUS" : "FAHRENHEIT";
        }

        const double initialBottomMargin = -100;
        private void ResetView()
        {
            showWeatherDetails = false;
            ConditionGrid.Margin = new Thickness(0, 0, 0, initialBottomMargin);
            ImageInfo.Opacity = 0;
        }

        #endregion

        Storyboard sb = null;
        private void Image_ImageOpened_1(object sender, RoutedEventArgs e)
        {
            if (sb != null) return;
            Control im = (Control)sender;
            sb = new Storyboard();
            DoubleAnimation da = new DoubleAnimation { 
                From = 0, To = 360, 
                Duration = new Duration(TimeSpan.FromSeconds(25)), 
                RepeatBehavior = RepeatBehavior.Forever 
            };
            Storyboard.SetTarget(da, im.RenderTransform);
            Storyboard.SetTargetProperty(da, new PropertyPath("Angle"));
            sb.Children.Add(da);
            sb.Begin();
        }

        private void Retry_Click(object sender, RoutedEventArgs e)
        {
            WeatherItem wi = DataContext as WeatherItem;
            if (wi == null) return;
            wi.ErrorText = null;
            wi.IsWaitingForWeather = true;
            if (wi.WeatherCondition == null)
            {
                // error was - could not get weather
                App.ViewModel.TryGetWeather();
            }
            else
            {
                // error was - could not retrieve image
                // how do we force a reload?
                WeatherImage.Source = new BitmapImage(new Uri(wi.ImageUri));
            }
        }

        internal void Image_ImageFailed(object sender, ExceptionRoutedEventArgs e)
        {
            var wi = (WeatherItem)DataContext;
            wi.IsWaitingForWeather = false;
            wi.ErrorText = "Could not load weather image.";
        }

        internal void OnImageUriChanged()
        {
            var wi = (WeatherItem)DataContext;
            if (wi.ImageUri == null) WeatherImageMedium.Source = null;// Visibility = Visibility.Collapsed;
        }

        public static readonly DependencyProperty MyHorizontalOffsetProperty =
            DependencyProperty.RegisterAttached("MyHorizontalOffset", typeof(double), typeof(WeatherItemView),
            new PropertyMetadata(new PropertyChangedCallback(OnMyHorizontalOffsetChanged)));

        public static double GetMyHorizontalOffset(ScrollViewer sv)
        {
            return (double)sv.GetValue(MyHorizontalOffsetProperty); 
        }

        public static void SetMyHorizontalOffset(ScrollViewer sv, double value) {
            sv.SetValue(MyHorizontalOffsetProperty, value);
//            sv.ScrollToHorizontalOffset(value);
        }

        private static void OnMyHorizontalOffsetChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        { 
            ScrollViewer sv = (ScrollViewer)obj;
            sv.ScrollToHorizontalOffset((double)args.NewValue); 
        }

        bool showWeatherDetails = false;
        bool ShowWeatherDetails
        {
            get { return showWeatherDetails; }
            set
            {
                if (showWeatherDetails == value) return;
                showWeatherDetails = value;
                AnimateTranslation(0.2, ConditionGrid, 0, showWeatherDetails ? 0 : initialBottomMargin, 15);
            }
        }

        private void HighVisWeatherIcon_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            ShowWeatherDetails = !ShowWeatherDetails;
        }


        private void WeatherImage_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            ShowWeatherDetails = false;
        }

        private void HideDetailsClick(object sender, RoutedEventArgs e)
        {
            ShowWeatherDetails = false;
        }
    }

    

    public class VisConverter : IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            bool v = false;
            if (parameter != null)
            {
                string p = parameter.ToString();
                if (p.StartsWith("!"))
                {
                    v = p.Substring(1) != value.ToString();
                }
                else
                {
                    v = p.Equals(value.ToString());
                }
            } else {
                v = (bool)value;
            }
            return v ? Visibility.Visible : Visibility.Collapsed;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion
    }


    public class EqualityConverter : IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            bool v = false;
            if (parameter != null)
            {
                string p = parameter.ToString();
                if (p.StartsWith("!"))
                {
                    v = p.Substring(1) != value.ToString();
                }
                else
                {
                    v = p == value.ToString();
                }
            }
            else
            {
                v = false;
            }
            return v;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion
    }



}
